#include "display_oled.h"
#include "u8g2.h"
#include "gd32f310_bsp_i2c.h"
#include "gd32f310_bsp_adc.h"
#include "systick.h"

#define I2C0_OWN_ADDRESS7 0x72
#define I2C0_SLAVE_ADDRESS7 0x78

#define GPIO_RCU_SCL RCU_GPIOA
#define GPIO_RCU_SDA RCU_GPIOA
#define GPIO_PERIPH_SCL GPIOA
#define GPIO_PERIPH_SDA GPIOA
#define GPIO_PIN_SCL GPIO_PIN_9
#define GPIO_PIN_SDA GPIO_PIN_10

#define SRC_OFFSET_Y 4

u8g2_t u8g2;

uint8_t u8x8_gpio_and_delay_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
uint8_t u8x8_gpio_and_delay_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);

extern uint16_t num_of_bullet;
extern uint16_t adc_value_max;
extern uint16_t number_of_point;
extern uint16_t time_of_wave;
extern uint16_t result_buffer[10];

void u8g2_loop(void)
{
    char temp[64];

    u8g2_ClearBuffer((u8g2_t *)&u8g2); // 先清除缓冲区数据

    u8g2_DrawRFrame(&u8g2, 0, 0, 128, 64, 4); // 显示圆角空心矩形

    u8g2_SetFont(&u8g2, u8g2_font_5x7_mf); // 设置字体
    sprintf(temp, "raw   : %d", adc_value_raw[0]);
    u8g2_DrawStr(&u8g2, 9, SRC_OFFSET_Y + 10, temp); // 显示字符串
    sprintf(temp, "max   : %d", adc_value_max);
    u8g2_DrawStr(&u8g2, 9, SRC_OFFSET_Y + 20, temp); // 显示字符串
    sprintf(temp, "cnt   : %d", num_of_bullet);
    u8g2_DrawStr(&u8g2, 9, SRC_OFFSET_Y + 30, temp); // 显示字符串
    sprintf(temp, "point : %d", number_of_point);
    u8g2_DrawStr(&u8g2, 9, SRC_OFFSET_Y + 40, temp); // 显示字符串
    sprintf(temp, "time  : %.1f", time_of_wave / 1000.0f);
    u8g2_DrawStr(&u8g2, 9, SRC_OFFSET_Y + 50, temp); // 显示字符串

    u8g2_DrawLine(&u8g2, 75, 5, 75, 64 - 5);

    sprintf(temp, "%d", result_buffer[0]);
    u8g2_DrawStr(&u8g2, 85, SRC_OFFSET_Y + 10, temp); // 显示字符串
    sprintf(temp, "%d", result_buffer[1]);
    u8g2_DrawStr(&u8g2, 85, SRC_OFFSET_Y + 20, temp); // 显示字符串
    sprintf(temp, "%d", result_buffer[2]);
    u8g2_DrawStr(&u8g2, 85, SRC_OFFSET_Y + 30, temp); // 显示字符串
    sprintf(temp, "%d", result_buffer[3]);
    u8g2_DrawStr(&u8g2, 85, SRC_OFFSET_Y + 40, temp); // 显示字符串
    sprintf(temp, "%d", result_buffer[4]);
    u8g2_DrawStr(&u8g2, 85, SRC_OFFSET_Y + 50, temp); // 显示字符串

    u8g2_DrawLine(&u8g2, 110, 10, 115, 10);
    u8g2_DrawLine(&u8g2, 110, 10, 112, 8);
    u8g2_DrawLine(&u8g2, 110, 10, 112, 12);

    u8g2_SendBuffer((u8g2_t *)&u8g2); // 发送缓冲区数据到屏幕
}

void u8g2_init(u8g2_t *u8g2)
{
    // 初始化 u8g2 结构体
    u8g2_Setup_ssd1309_i2c_128x64_noname0_f(u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_sw_i2c);
    // u8g2_Setup_ssd1309_i2c_128x64_noname0_f(u8g2, U8G2_R2, u8x8_byte_hw_i2c, u8x8_gpio_and_delay_hw_i2c);
    u8g2_InitDisplay(u8g2);               // 根据所选的芯片进行初始化工作，初始化完成后，显示器处于关闭状态
    u8g2_SetPowerSave(u8g2, 0);           // 打开显示器
    u8g2_SetFont(u8g2, u8g2_font_5x7_mf); // 设置字体
    u8g2_SetFontDirection(u8g2, 0);       // 字体方向向右
}

void display_oled_init(void)
{
    u8g2_init(&u8g2); // u8g2初始化
}

void sw_i2c_init(void)
{
    rcu_periph_clock_enable(GPIO_RCU_SCL);
    rcu_periph_clock_enable(GPIO_RCU_SDA);
    // SCL
    gpio_mode_set(GPIO_PERIPH_SCL, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_SCL);
    gpio_output_options_set(GPIO_PERIPH_SCL, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_SCL);
    // SDA
    gpio_mode_set(GPIO_PERIPH_SDA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_SDA);
    gpio_output_options_set(GPIO_PERIPH_SDA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_SDA);
    // DEFAULT HIGH
    gpio_bit_write(GPIO_PERIPH_SCL, GPIO_PIN_SCL, SET);
    gpio_bit_write(GPIO_PERIPH_SDA, GPIO_PIN_SDA, SET);
}

uint8_t u8x8_gpio_and_delay_sw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    switch (msg)
    {
    case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
        sw_i2c_init();
        break;                 // can be used to setup pins
    case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
        // delay_1ms(arg_int);
        delay_1us(1000);
        break;
    case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
        delay_1us(5);
        break;                // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
    case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
        break;
    case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
        gpio_bit_write(GPIO_PERIPH_SCL, GPIO_PIN_SCL, (bit_status)arg_int);
        break;                   // arg_int=1: Input dir with pullup high for I2C clock pin
    case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin
        gpio_bit_write(GPIO_PERIPH_SDA, GPIO_PIN_SDA, (bit_status)arg_int);
        break; // arg_int=1: Input dir with pullup high for I2C data pin
    default:
        u8x8_SetGPIOResult(u8x8, 1); // default return value
        break;
    }
    return 1;
}

#if 0

uint8_t u8x8_gpio_and_delay_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    switch (msg)
    {
    case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
        break;
    case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
        break;
    case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
        delay_1ms(1);
        break;
    case U8X8_MSG_DELAY_I2C:      // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
        break;                    // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
    case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
        break;                    // arg_int=1: Input dir with pullup high for I2C clock pin
    case U8X8_MSG_GPIO_I2C_DATA:  // arg_int=0: Output low at I2C data pin
        break;                    // arg_int=1: Input dir with pullup high for I2C data pin
    case U8X8_MSG_GPIO_MENU_SELECT:
        u8x8_SetGPIOResult(u8x8, /* get menu select pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_NEXT:
        u8x8_SetGPIOResult(u8x8, /* get menu next pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_PREV:
        u8x8_SetGPIOResult(u8x8, /* get menu prev pin state */ 0);
        break;
    case U8X8_MSG_GPIO_MENU_HOME:
        u8x8_SetGPIOResult(u8x8, /* get menu home pin state */ 0);
        break;
    default:
        u8x8_SetGPIOResult(u8x8, 1); // default return value
        break;
    }
    return 1;
}


uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
    uint8_t *data = (uint8_t *)arg_ptr;
    switch (msg)
    {
    case U8X8_MSG_BYTE_SEND:
        while (arg_int-- > 0)
        {
            /* data transmission */
            i2c_data_transmit(I2C0, (*data++));
            /* wait until the TBE bit is set */
            while (!i2c_flag_get(I2C0, I2C_FLAG_TBE))
                ;
        }
        break;
    case U8X8_MSG_BYTE_INIT:
        /* add your custom code to init i2c subsystem */
        bsp_i2c_init();
        break;
    case U8X8_MSG_BYTE_SET_DC:
        /* ignored for i2c */
        break;
    case U8X8_MSG_BYTE_START_TRANSFER:
        // while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY))
        //     ;
        // I2C_GenerateSTART(I2C1, ENABLE);
        // while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
        //     continue;
        // I2C_Send7bitAddress(I2C1, 0x78, I2C_Direction_Transmitter);
        // while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
        //     continue;

        /* enable I2C0 */
        i2c_enable(I2C0);
        /* enable acknowledge */
        i2c_ack_config(I2C0, I2C_ACK_ENABLE);

        /* wait until I2C bus is idle */
        while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY))
            ;
        /* send a start condition to I2C bus */
        i2c_start_on_bus(I2C0);
        /* wait until SBSEND bit is set */
        while (!i2c_flag_get(I2C0, I2C_FLAG_SBSEND))
            ;
        /* send slave address to I2C bus */
        i2c_master_addressing(I2C0, I2C0_SLAVE_ADDRESS7, I2C_TRANSMITTER);
        //        /* wait until ADDSEND bit is set */
        //        while (!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND))
        //            ;
        //        /* clear ADDSEND bit */
        i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
        /* wait until the transmit data buffer is empty */
        //        while (!i2c_flag_get(I2C0, I2C_FLAG_TBE))
        //            ;

        break;
    case U8X8_MSG_BYTE_END_TRANSFER:
        // I2C_GenerateSTOP(I2C1, ENABLE);

        /* send a stop condition to I2C bus */
        i2c_stop_on_bus(I2C0);
        while (I2C_CTL0(I2C0) & I2C_CTL0_STOP)
            ;

        break;
    default:
        return 0;
    }
    return 1;
}
#endif